package com.share.order.receiver;

import com.alibaba.fastjson2.JSONObject;
import com.rabbitmq.client.Channel;
import com.share.common.rabbit.MqConstant.MqConst;
import com.share.order.domain.EndOrderVo;
import com.share.order.domain.SubmitOrderVo;
import com.share.order.service.IOrderInfoService;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.Exchange;
import org.springframework.amqp.rabbit.annotation.Queue;
import org.springframework.amqp.rabbit.annotation.QueueBinding;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

import java.util.concurrent.TimeUnit;

@Slf4j
@Component
public class OrderReceiver {


    @Autowired
    private IOrderInfoService orderInfoService;

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private RedissonClient redissonClient;

    @SneakyThrows
    @RabbitListener(bindings = @QueueBinding(
            exchange = @Exchange(value = MqConst.EXCHANGE_ORDER, durable = "true"),
            value = @Queue(value = MqConst.QUEUE_SUBMIT_ORDER, durable = "true"),
            key = MqConst.ROUTING_SUBMIT_ORDER
    ))
    public void submitOrder(String content, Message message, Channel channel) {
        // 获取 correlationId
        String correlationId = message.getMessageProperties().getCorrelationId();
        SubmitOrderVo orderForm = JSONObject.parseObject(content, SubmitOrderVo.class);
        String messageNo = orderForm.getMessageNo();
        //防止重复请求，以mq消息的唯一id作为key
        String key = "order:lock:" + message.getMessageProperties().getDeliveryTag();
        boolean isExist = redisTemplate.opsForValue().setIfAbsent(key, messageNo, 1, TimeUnit.HOURS);
        if (!isExist) {
            log.info("重复请求: {}", content);
            return;
        }
        RLock lock = redissonClient.getLock("order:lock:" + correlationId);
        try {
            if (lock.tryLock(10, 5, TimeUnit.SECONDS)) {
                try {
                    /**
                     * 正常逻辑
                     */
                    log.info("[订单服务]租借充电宝消息：{}", content);
                    orderInfoService.saveOrder(orderForm);
                    //手动应答
                    channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);

                } catch (Exception e) {
                    log.error("订单服务：订单归还失败，消息编号：{}", correlationId, e);
                    // 消费异常，重新入队
                    channel.basicNack(message.getMessageProperties().getDeliveryTag(), false, true);
                } finally {
                    // Redisson会自动处理锁的释放
                    lock.unlock();
                }
                return;
            }else {
                log.info("[订单服务]获取锁失败，重复订单{}", correlationId);
            }
        } catch (InterruptedException e) {
            log.error("[订单服务]获取锁失败{}", correlationId, e);
            return;
        }

    }

    /**
     * 归还充电宝，修改订单状态，计算费用金额，创建订单账单
     * @param content
     * @param message
     * @param channel
     */
    @SneakyThrows
    @RabbitListener(bindings = @QueueBinding(
            exchange = @Exchange(value = MqConst.EXCHANGE_ORDER, durable = "true"),
            value = @Queue(value = MqConst.QUEUE_END_ORDER, durable = "true"),
            key = MqConst.ROUTING_END_ORDER
    ))
    private void endOrder(String content, Message message, Channel channel){
        log.info("[订单服务]归还充电宝消息：{}", content);
        EndOrderVo endOrderVo = JSONObject.parseObject(content, EndOrderVo.class);
        String messageNo = endOrderVo.getMessageNo();
        //防止重复请求
        String key = "order:endOrder:" + messageNo;
        boolean isExist = redisTemplate.opsForValue().setIfAbsent(key, messageNo, 1, TimeUnit.HOURS);
        if (!isExist) {
            log.info("重复请求: {}", content);
            return;
        }
        // 添加分布式锁
        RLock lock = redissonClient.getLock("order:endOrder:lock:" + messageNo);
        try {
            // 尝试获取锁，等待10秒，锁自动过期时间5秒
            if (lock.tryLock(10, 5, TimeUnit.SECONDS)) {
                try {
                    orderInfoService.endOrder(endOrderVo);
                    //手动应答
                    channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
                } catch (Exception e) {
                    log.error("订单服务：订单归还失败，订单编号：{}", messageNo, e);
                    redisTemplate.delete(key);
                    // 消费异常，重新入队
                    channel.basicNack(message.getMessageProperties().getDeliveryTag(), false, true);
                } finally {
                    // 释放锁
                    if (lock.isHeldByCurrentThread()) {
                        lock.unlock();
                    }
                }
            } else {
                log.warn("获取分布式锁失败，订单编号：{}", messageNo);
                // 获取锁失败，重新入队等待下次处理
                channel.basicNack(message.getMessageProperties().getDeliveryTag(), false, true);
            }
        } catch (InterruptedException e) {
            log.error("获取分布式锁被中断{}", messageNo, e);
            Thread.currentThread().interrupt();
            // 中断异常，重新入队
            channel.basicNack(message.getMessageProperties().getDeliveryTag(), false, true);
        }
    }



}
